home *** CD-ROM | disk | FTP | other *** search
- /* $Id: plstring.c,v 1.8 1994/06/30 18:22:18 mjl Exp $
- * $Log: plstring.c,v $
- * Revision 1.8 1994/06/30 18:22:18 mjl
- * All core source files: made another pass to eliminate warnings when using
- * gcc -Wall. Lots of cleaning up: got rid of includes of math.h or string.h
- * (now included by plplot.h), and other minor changes. Now each file has
- * global access to the plstream pointer via extern; many accessor functions
- * eliminated as a result.
- *
- * Revision 1.7 1994/03/23 08:34:00 mjl
- * All external API source files: replaced call to plexit() on simple
- * (recoverable) errors with simply printing the error message (via
- * plabort()) and returning. Should help avoid loss of computer time in some
- * critical circumstances (during a long batch run, for example).
- */
-
- /* plstring.c
-
- Text & string handling routines.
- */
-
- #include "plplotP.h"
- #include <ctype.h>
-
- #define PLMAXSTR 300
- #define STLEN 250
-
- static char font[] = "nris";
- static char greek[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw";
- static short symbol[PLMAXSTR];
- static SCHAR xygrid[STLEN];
-
- extern SCHAR *fntbffr;
- extern short int *fntindx;
- extern short int indxleng;
- extern short int *fntlkup;
- extern short int numberfonts, numberchars;
-
- /* Static function prototypes */
-
- static void pldeco (short **, PLINT *, const char *);
- static void plchar (SCHAR *, PLFLT *, PLINT, PLINT, PLINT,
- PLINT, PLINT, PLFLT, PLFLT, PLFLT, PLFLT, PLFLT,
- PLFLT *, PLFLT *, PLFLT *);
-
- /*----------------------------------------------------------------------*\
- * void pllab()
- *
- * Simple routine for labelling graphs.
- \*----------------------------------------------------------------------*/
-
- void
- c_pllab(const char *xlabel, const char *ylabel, const char *tlabel)
- {
- if (plsc->level < 2) {
- plabort("pllab: Please set up viewport first");
- return;
- }
-
- plmtex("t", (PLFLT) 2.0, (PLFLT) 0.5, (PLFLT) 0.5, tlabel);
- plmtex("b", (PLFLT) 3.2, (PLFLT) 0.5, (PLFLT) 0.5, xlabel);
- plmtex("l", (PLFLT) 5.0, (PLFLT) 0.5, (PLFLT) 0.5, ylabel);
- }
-
- /*----------------------------------------------------------------------*\
- * void plmtex()
- *
- * Prints out "text" at specified position relative to viewport
- * (may be inside or outside)
- *
- * side String which is one of the following:
- * B or b : Bottom of viewport
- * T or t : Top of viewport
- * L or l : Left of viewport
- * R or r : Right of viewport
- * LV or lv : Left of viewport, vertical text
- * RV or rv : Right of viewport, vertical text
- * disp Displacement from specified edge of viewport, measured
- * outwards from the viewport in units of the current
- * character height. The centerlines of the characters are
- * aligned with the specified position.
- * pos Position of the reference point of the string relative
- * to the viewport edge, ranging from 0.0 (left-hand edge)
- * to 1.0 (right-hand edge)
- * just Justification of string relative to reference point
- * just = 0.0 => left hand edge of string is at reference
- * just = 1.0 => right hand edge of string is at reference
- * just = 0.5 => center of string is at reference
- \*----------------------------------------------------------------------*/
-
- void
- c_plmtex(const char *side, PLFLT disp, PLFLT pos, PLFLT just,
- const char *text)
- {
- PLINT clpxmi, clpxma, clpymi, clpyma;
- PLINT sppxmi, sppxma, sppymi, sppyma;
- PLINT vert, refx, refy;
- PLFLT shift, xform[4];
- PLFLT vpdxmi, vpdxma, vpdymi, vpdyma;
- PLFLT chrdef, chrht;
- PLFLT mpxscl, mpxoff, mpyscl, mpyoff;
-
- if (plsc->level < 2) {
- plabort("plmtex: Please set up viewport first");
- return;
- }
-
- /* Open clip limits to subpage limits */
-
- plP_gclp(&clpxmi, &clpxma, &clpymi, &clpyma);
- plP_gspp(&sppxmi, &sppxma, &sppymi, &sppyma);
- plP_sclp(sppxmi, sppxma, sppymi, sppyma);
-
- plP_gvpd(&vpdxmi, &vpdxma, &vpdymi, &vpdyma);
- plP_gmp(&mpxscl, &mpxoff, &mpyscl, &mpyoff);
- plgchr(&chrdef, &chrht);
-
- shift = 0.0;
- if (just != 0.0)
- shift = just * plstrl(text);
-
- if (plP_stsearch(side, 'b')) {
- vert = 0;
- refx = plP_dcpcx((PLFLT) (vpdxmi + (vpdxma - vpdxmi) * pos)) -
- shift * mpxscl;
- refy = plP_mmpcy((PLFLT) (plP_dcmmy(vpdymi) - disp * chrht));
- }
- else if (plP_stsearch(side, 't')) {
- vert = 0;
- refx = plP_dcpcx((PLFLT) (vpdxmi + (vpdxma - vpdxmi) * pos)) -
- shift * mpxscl;
- refy = plP_mmpcy((PLFLT) (plP_dcmmy(vpdyma) + disp * chrht));
- }
- else if (plP_stindex(side, "LV") != -1 || plP_stindex(side, "lv") != -1) {
- vert = 0;
- refy = plP_dcpcy((PLFLT) (vpdymi + (vpdyma - vpdymi) * pos));
- refx = plP_mmpcx((PLFLT) (plP_dcmmx(vpdxmi) - disp * chrht - shift));
- }
- else if (plP_stindex(side, "RV") != -1 || plP_stindex(side, "rv") != -1) {
- vert = 0;
- refy = plP_dcpcy((PLFLT) (vpdymi + (vpdyma - vpdymi) * pos));
- refx = plP_mmpcx((PLFLT) (plP_dcmmx(vpdxma) + disp * chrht - shift));
- }
- else if (plP_stsearch(side, 'l')) {
- vert = 1;
- refy = plP_dcpcy((PLFLT) (vpdymi + (vpdyma - vpdymi) * pos)) -
- shift * mpyscl;
- refx = plP_mmpcx((PLFLT) (plP_dcmmx(vpdxmi) - disp * chrht));
- }
- else if (plP_stsearch(side, 'r')) {
- vert = 1;
- refy = plP_dcpcy((PLFLT) (vpdymi + (vpdyma - vpdymi) * pos)) -
- shift * mpyscl;
- refx = plP_mmpcx((PLFLT) (plP_dcmmx(vpdxma) + disp * chrht));
- }
- else {
- plP_sclp(clpxmi, clpxma, clpymi, clpyma);
- return;
- }
-
- if (vert != 0) {
- xform[0] = 0.0;
- xform[1] = -1.0;
- xform[2] = 1.0;
- xform[3] = 0.0;
- }
- else {
- xform[0] = 1.0;
- xform[1] = 0.0;
- xform[2] = 0.0;
- xform[3] = 1.0;
- }
- plstr(0, xform, refx, refy, text);
- plP_sclp(clpxmi, clpxma, clpymi, clpyma);
- }
-
- /*----------------------------------------------------------------------*\
- * void plptex()
- *
- * Prints out "text" at world cooordinate (x,y). The text may be
- * at any angle "angle" relative to the horizontal. The parameter
- * "just" adjusts the horizontal justification of the string:
- * just = 0.0 => left hand edge of string is at (x,y)
- * just = 1.0 => right hand edge of string is at (x,y)
- * just = 0.5 => center of string is at (x,y) etc.
- \*----------------------------------------------------------------------*/
-
- void
- c_plptex(PLFLT x, PLFLT y, PLFLT dx, PLFLT dy, PLFLT just, const char *text)
- {
- PLINT refx, refy;
- PLFLT shift, cc, ss;
- PLFLT xform[4], diag;
- PLFLT xscl, xoff, yscl, yoff;
-
- if (plsc->level < 3) {
- plabort("plptex: Please set up window first");
- return;
- }
-
- plP_gwm(&xscl, &xoff, &yscl, &yoff);
-
- if (dx == 0.0 && dy == 0.0) {
- dx = 1.0;
- dy = 0.0;
- }
- cc = xscl * dx;
- ss = yscl * dy;
- diag = sqrt(cc * cc + ss * ss);
- cc = cc / diag;
- ss = ss / diag;
-
- plP_gmp(&xscl, &xoff, &yscl, &yoff);
- shift = 0.0;
-
- xform[0] = cc;
- xform[1] = -ss;
- xform[2] = ss;
- xform[3] = cc;
-
- if (just != 0.0)
- shift = plstrl(text) * just;
- refx = plP_wcpcx(x) - shift * cc * xscl;
- refy = plP_wcpcy(y) - shift * ss * yscl;
- plstr(0, xform, refx, refy, text);
- }
-
- /*----------------------------------------------------------------------*\
- * void plstr()
- *
- * Prints out a "string" at reference position with physical coordinates
- * (refx,refy). The coordinates of the vectors defining the string are
- * passed through the linear mapping defined by the 2 x 2 matrix xform()
- * before being plotted. The reference position is at the left-hand edge of
- * the string. If base = 1, it is aligned with the baseline of the string.
- * If base = 0, it is aligned with the center of the character box.
- *
- * Note, all calculations are done in terms of millimetres. These are scaled
- * as necessary before plotting the string on the page.
- \*----------------------------------------------------------------------*/
-
- void
- plstr(PLINT base, PLFLT *xform, PLINT refx, PLINT refy, const char *string)
- {
- short int *symbol;
- SCHAR *xygrid;
- PLINT ch, i, length, level, style, oline, uline;
- PLFLT width, xorg, yorg, def, ht, dscale, scale;
- PLFLT xscl, xoff, yscl, yoff;
-
- width = 0.0;
- oline = 0;
- uline = 0;
-
- plgchr(&def, &ht);
- dscale = 0.05 * ht;
- scale = dscale;
- plP_gmp(&xscl, &xoff, &yscl, &yoff);
-
- /* Line style must be continuous */
-
- style = plsc->nms;
- plsc->nms = 0;
-
- pldeco(&symbol, &length, string);
- xorg = 0.0;
- yorg = 0.0;
- level = 0;
-
- for (i = 0; i < length; i++) {
- ch = symbol[i];
- if (ch == -1) {
- level = level + 1;
- yorg = yorg + 16.0 * scale;
- scale = dscale * pow(0.75, (double) ABS(level));
- }
- else if (ch == -2) {
- level = level - 1;
- scale = dscale * pow(0.75, (double) ABS(level));
- yorg = yorg - 16.0 * scale;
- }
- else if (ch == -3)
- xorg = xorg - width * scale;
- else if (ch == -4)
- oline = !oline;
- else if (ch == -5)
- uline = !uline;
- else {
- if (plcvec(ch, &xygrid))
- plchar(xygrid, xform, base, oline, uline, refx, refy, scale,
- xscl, xoff, yscl, yoff, &xorg, &yorg, &width);
- }
- }
- plsc->nms = style;
- }
-
- /*----------------------------------------------------------------------*\
- * plchar()
- *
- * Plots out a given stroke font character.
- \*----------------------------------------------------------------------*/
-
- static void
- plchar(SCHAR *xygrid, PLFLT *xform, PLINT base, PLINT oline, PLINT uline,
- PLINT refx, PLINT refy, PLFLT scale,
- PLFLT xscl, PLFLT xoff, PLFLT yscl, PLFLT yoff,
- PLFLT *p_xorg, PLFLT *p_yorg, PLFLT *p_width)
- {
- PLINT xbase, ybase, ydisp, lx, ly, cx, cy;
- PLINT k, penup;
- PLFLT x, y;
-
- xbase = xygrid[2];
- *p_width = xygrid[3] - xbase;
- if (base == 0) {
- ybase = 0;
- ydisp = xygrid[0];
- }
- else {
- ybase = xygrid[0];
- ydisp = 0;
- }
- k = 4;
- penup = 1;
- for (;;) {
- cx = xygrid[k++];
- cy = xygrid[k++];
- if (cx == 64 && cy == 64)
- break;
- if (cx == 64 && cy == 0)
- penup = 1;
- else {
- x = *p_xorg + (cx - xbase) * scale;
- y = *p_yorg + (cy - ybase) * scale;
- lx = refx + ROUND(xscl * (xform[0] * x + xform[1] * y));
- ly = refy + ROUND(yscl * (xform[2] * x + xform[3] * y));
- if (penup != 0) {
- plP_movphy(lx, ly);
- penup = 0;
- }
- else
- plP_draphy(lx, ly);
- }
- }
-
- if (oline) {
- x = *p_xorg;
- y = *p_yorg + (30 + ydisp) * scale;
- lx = refx + ROUND(xscl * (xform[0] * x + xform[1] * y));
- ly = refy + ROUND(yscl * (xform[2] * x + xform[3] * y));
- plP_movphy(lx, ly);
- x = *p_xorg + *p_width * scale;
- lx = refx + ROUND(xscl * (xform[0] * x + xform[1] * y));
- ly = refy + ROUND(yscl * (xform[2] * x + xform[3] * y));
- plP_draphy(lx, ly);
- }
- if (uline) {
- x = *p_xorg;
- y = *p_yorg + (-5 + ydisp) * scale;
- lx = refx + ROUND(xscl * (xform[0] * x + xform[1] * y));
- ly = refy + ROUND(yscl * (xform[2] * x + xform[3] * y));
- plP_movphy(lx, ly);
- x = *p_xorg + *p_width * scale;
- lx = refx + ROUND(xscl * (xform[0] * x + xform[1] * y));
- ly = refy + ROUND(yscl * (xform[2] * x + xform[3] * y));
- plP_draphy(lx, ly);
- }
- *p_xorg = *p_xorg + *p_width * scale;
- }
-
- /*----------------------------------------------------------------------*\
- * PLFLT plstrl()
- *
- * Computes the length of a string in mm, including escape sequences.
- \*----------------------------------------------------------------------*/
-
- PLFLT
- plstrl(const char *string)
- {
- short int *symbol;
- SCHAR *xygrid;
- PLINT ch, i, length, level;
- PLFLT width, xorg, dscale, scale, def, ht;
- PLFLT xscl, xoff, yscl, yoff;
-
- width = 0.0;
- plgchr(&def, &ht);
- dscale = 0.05 * ht;
- scale = dscale;
- plP_gmp(&xscl, &xoff, &yscl, &yoff);
-
- pldeco(&symbol, &length, string);
- xorg = 0.0;
- level = 0;
-
- for (i = 0; i < length; i++) {
- ch = symbol[i];
- if (ch == -1) {
- level = level + 1;
- scale = dscale * pow(0.75, (double) ABS(level));
- }
- else if (ch == -2) {
- level = level - 1;
- scale = dscale * pow(0.75, (double) ABS(level));
- }
- else if (ch == -3)
- xorg = xorg - width * scale;
- else if (ch == -4 || ch == -5);
- else {
- if (plcvec(ch, &xygrid)) {
- width = xygrid[3] - xygrid[2];
- xorg = xorg + width * scale;
- }
- }
- }
- return ((PLFLT) xorg);
- }
-
- /*----------------------------------------------------------------------*\
- * PLINT plcvec()
- *
- * Gets the character digitisation of Hershey table entry "char".
- * Returns 1 if there is a valid entry.
- \*----------------------------------------------------------------------*/
-
- PLINT
- plcvec(PLINT ch, SCHAR ** xygr)
- {
- PLINT k, ib;
- SCHAR x, y;
-
- ch--;
- if (ch < 0 || ch >= indxleng)
- return ((PLINT) 0);
- ib = fntindx[ch] - 2;
- if (ib == -2)
- return ((PLINT) 0);
-
- k = 0;
- do {
- ib++;
- x = fntbffr[2 * ib];
- y = fntbffr[2 * ib + 1];
- xygrid[k++] = x;
- xygrid[k++] = y;
- } while ((x != 64 || y != 64) && k <= (STLEN - 2));
-
- *xygr = xygrid;
- return ((PLINT) 1);
- }
-
- /*----------------------------------------------------------------------*\
- * void pldeco()
- *
- * Decode a character string, and return an array of float integer symbol
- * numbers. This routine is responsible for interpreting all escape sequences.
- * At present the following escape sequences are defined (the letter following
- * the <esc> may be either upper or lower case):
- *
- * <esc>u : up one level (returns -1)
- * <esc>d : down one level (returns -2)
- * <esc>b : backspace (returns -3)
- * <esc>+ : toggles overline mode (returns -4)
- * <esc>- : toggles underline mode (returns -5)
- * <esc><esc> : <esc>
- * <esc>gx : greek letter corresponding to roman letter x
- * <esc>fn : switch to Normal font
- * <esc>fr : switch to Roman font
- * <esc>fi : switch to Italic font
- * <esc>fs : switch to Script font
- * <esc>(nnn) : Hershey symbol number nnn (any number of digits)
- *
- * The escape character defaults to '#', but can be changed to any of
- * [!#$%&*@^~] via a call to plsesc.
- \*----------------------------------------------------------------------*/
-
- static void
- pldeco(short int **sym, PLINT *length, const char *text)
- {
- PLINT ch, icol, ifont, ig, j, lentxt;
- char test, esc;
-
- /* Initialize parameters. */
-
- lentxt = strlen(text);
- *length = 0;
- *sym = symbol;
- plP_gatt(&ifont, &icol);
- plgesc(&esc);
- if (ifont > numberfonts)
- ifont = 1;
-
- /* Get next character; treat non-printing characters as spaces. */
-
- j = 0;
- while (j < lentxt) {
- if (*length >= PLMAXSTR)
- return;
- test = text[j++];
- ch = test;
- if (ch < 0 || ch > 175)
- ch = 32;
-
- /* Test for escape sequence (#) */
-
- if (ch == esc && (lentxt - j) >= 1) {
- test = text[j++];
- if (test == esc)
- symbol[(*length)++] = *(fntlkup + (ifont - 1) * numberchars + ch);
-
- else if (test == 'u' || test == 'U')
- symbol[(*length)++] = -1;
-
- else if (test == 'd' || test == 'D')
- symbol[(*length)++] = -2;
-
- else if (test == 'b' || test == 'B')
- symbol[(*length)++] = -3;
-
- else if (test == '+')
- symbol[(*length)++] = -4;
-
- else if (test == '-')
- symbol[(*length)++] = -5;
-
- else if (test == '(') {
- symbol[*length] = 0;
- while ('0' <= text[j] && text[j] <= '9') {
- symbol[*length] = symbol[*length] * 10 + text[j] - '0';
- j++;
- }
- (*length)++;
- if (text[j] == ')')
- j++;
- }
- else if (test == 'f' || test == 'F') {
- test = text[j++];
- ifont = plP_strpos(font, isupper(test) ? tolower(test) : test) + 1;
- if (ifont == 0 || ifont > numberfonts)
- ifont = 1;
- }
- else if (test == 'g' || test == 'G') {
- test = text[j++];
- ig = plP_strpos(greek, test) + 1;
- symbol[(*length)++] = *(fntlkup + (ifont - 1) * numberchars +
- 127 + ig);
- }
- else {
- ;
- }
- }
- else {
-
- /* Decode character. */
- /* >>PC<< removed increment from following expression to fix compiler bug */
-
- symbol[(*length)] = *(fntlkup + (ifont - 1) * numberchars + ch);
- (*length)++;
- }
- }
- }
-
- /*----------------------------------------------------------------------*\
- * PLINT plP_strpos()
- *
- * Searches string str for first occurence of character chr. If found
- * the position of the character in the string is returned (the first
- * character has position 0). If the character is not found a -1 is
- * returned.
- \*----------------------------------------------------------------------*/
-
- PLINT
- plP_strpos(char *str, int chr)
- {
- char *temp;
-
- if ((temp = strchr(str, chr)))
- return ((PLINT) (temp - str));
- else
- return ((PLINT) -1);
- }
-
- /*----------------------------------------------------------------------*\
- * PLINT plP_stindex()
- *
- * Similar to strpos, but searches for occurence of string str2.
- \*----------------------------------------------------------------------*/
-
- PLINT
- plP_stindex(const char *str1, const char *str2)
- {
- PLINT base;
- PLINT str1ind;
- PLINT str2ind;
-
- for (base = 0; *(str1 + base) != '\0'; base++) {
- for (str1ind = base, str2ind = 0; *(str2 + str2ind) != '\0' &&
- *(str2 + str2ind) == *(str1 + str1ind); str1ind++, str2ind++);
-
- /* no body */
-
- if (*(str2 + str2ind) == '\0')
- return ((PLINT) base);
- }
- return ((PLINT) -1); /* search failed */
- }
-
- /*----------------------------------------------------------------------*\
- * PLINT plP_stsearch()
- *
- * Searches string str for character chr (case insensitive).
- \*----------------------------------------------------------------------*/
-
- PLINT
- plP_stsearch(const char *str, int chr)
- {
- if (strchr(str, chr))
- return ((PLINT) 1);
- else if (strchr(str, toupper(chr)))
- return ((PLINT) 1);
- else
- return ((PLINT) 0);
- }
-